{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OSMnx features demo\n",
    "\n",
    "Author: [Rui Xu]\n",
    "\n",
    "More info:\n",
    "\n",
    "  - [Documentation](https://osmnx.readthedocs.io/)\n",
    "  - [Journal article and citation info](https://geoffboeing.com/publications/osmnx-paper/)\n",
    "  - [Code repository](https://github.com/gboeing/osmnx)\n",
    "  - [Examples gallery](https://github.com/gboeing/osmnx-examples)\n",
    "  \n",
    "This notebook provides a quick tour of some of OSMnx's key features including how to:\n",
    "\n",
    "  - 下载江苏地图\n",
    "  - 指定线路节点经纬度并对齐最近点\n",
    "  - 计算线路节点的最短路\n",
    "  - 作图展示保存为html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-09T06:35:01.976343600Z",
     "start_time": "2025-03-09T06:34:58.190572300Z"
    }
   },
   "outputs": [],
   "source": [
    "import networkx as nx\n",
    "import osmnx as ox\n",
    "import folium\n",
    "import geopandas as gpd"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 1. 下载江苏地图并保存为G"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\Administrator\\anaconda3\\envs\\ox\\Lib\\site-packages\\osmnx\\_overpass.py:267: UserWarning: This area is 69 times your configured Overpass max query area size. It will automatically be divided up into multiple sub-queries accordingly. This may take a long time.\n",
      "  multi_poly_proj = utils_geo._consolidate_subdivide_geometry(poly_proj)\n"
     ]
    }
   ],
   "source": [
    "place = \"Jiangsu, China\"\n",
    "if 0:\n",
    "    G3 = ox.graph.graph_from_place(place, custom_filter='[\"highway\"~\"motorway|primary\"]') # 快\n",
    "    G32 = G3.copy()\n",
    "if 1:\n",
    "    G2 = ox.graph.graph_from_place(place, network_type=\"drive\") # 满\n",
    "    G22 = G2.copy()\n",
    "if 0:\n",
    "    fig, ax = ox.plot.plot_graph(G2)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-09T07:01:04.803945600Z",
     "start_time": "2025-03-09T06:59:35.907640200Z"
    }
   },
   "execution_count": 50
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 2. 指定线路节点经纬度并对齐最近点\n",
    "## -. 指定坐标和文字名称\n",
    "## -. 寻找最近nodes和最短路routes\n",
    "## -. 提取geo_nodes得到route_nodes和route_edges"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "coordinates = [(118.809767, 31.902278), (119.709864, 31.525442), (119.972139, 31.844131), (118.809767, 31.902278)]\n",
    "supplyName = ['南京长安民生住久物流有限公司', '苏州振业楚硕科技有限公司', '大茂伟瑞柯车灯有限公司'] # supplyId = ['DC', 'KC701WX', 'KC641CZ', 'DC']"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-09T06:45:31.302745900Z",
     "start_time": "2025-03-09T06:45:31.290743500Z"
    }
   },
   "execution_count": 3
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "# 基于highways的地图G作图（快）\n",
    "G = G22.copy() # G=G32.copy()\n",
    "weight = \"length\"\n",
    "nodes = [ox.distance.nearest_nodes(G, X=lon, Y=lat) for lon, lat in coordinates]\n",
    "routes = []\n",
    "for i in range(len(nodes) - 1):\n",
    "    orig = nodes[i]\n",
    "    dest = nodes[i + 1]\n",
    "    route = nx.shortest_path(G, orig, dest, weight=weight)\n",
    "    routes.append(route)\n",
    "geo_nodes = ox.convert.graph_to_gdfs(G, edges=False)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-09T07:32:35.295342300Z",
     "start_time": "2025-03-09T07:32:01.997800500Z"
    }
   },
   "execution_count": 55
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "route_nodes = geo_nodes.loc[nodes]\n",
    "route_edges = (ox.routing.route_to_gdf(G, route, weight=weight) for route in routes) \n",
    "# 作图\n",
    "m = route_nodes.explore(marker_kwds={\"radius\": 8})  # tiles=\"cartodbpositron\"\n",
    "for aroute_edge in route_edges:\n",
    "    m = aroute_edge.explore(m=m, style_kwds={\"weight\": 5})\n",
    "# 遍历坐标列表，添加标记到地图\n",
    "if 1:\n",
    "    for i, (lon, lat) in enumerate(coordinates):\n",
    "        if i==len(coordinates)-1:\n",
    "            continue\n",
    "        folium.Marker(\n",
    "            location=(lat, lon),\n",
    "            popup=f\"{supplyName[i]}\",\n",
    "            icon=folium.Icon(color=\"blue\")\n",
    "        ).add_to(m)\n",
    "# 遍历坐标列表，添加带有固定显示文本的标记到地图\n",
    "for i, (lon, lat) in enumerate(coordinates):\n",
    "    if i==len(coordinates)-1:\n",
    "        continue\n",
    "    folium.Marker(\n",
    "        location=(lat, lon),\n",
    "        icon=folium.DivIcon(\n",
    "            html=f'''\n",
    "                <div style=\"\n",
    "                    font-size: 13px;\n",
    "                    color: red;\n",
    "                    padding: 2px;\n",
    "                    border-radius: 3px;\n",
    "                    white-space: nowrap;\n",
    "                \">\n",
    "                    {supplyName[i]}\n",
    "                </div>\n",
    "            '''\n",
    "        )\n",
    "    ).add_to(m)\n",
    "m.save(\"data/graphgCmsclRoute01.html\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-09T07:32:55.760048600Z",
     "start_time": "2025-03-09T07:32:55.443393300Z"
    }
   },
   "execution_count": 56
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "# 定义江苏省的主要城市\n",
    "jiangsu_cities = [\n",
    "    \"Nanjing, China\", \"Suzhou, China\", \"Wuxi, China\", \"Changzhou, China\",\n",
    "    \"Zhenjiang, China\", \"Yangzhou, China\", \"Taizhou,Jiangsu, China\", \"Nantong, China\",\n",
    "    \"Lianyungang, China\", \"Huaian, China\", \"Yancheng, China\", \"Suqian, China\",\n",
    "    \"Xuzhou, China\"\n",
    "]\n",
    "\n",
    "# 获取每个城市的边界并绘制到地图上\n",
    "for city in jiangsu_cities:\n",
    "    try:\n",
    "        gdf = ox.geocode_to_gdf(city)  # 获取城市边界\n",
    "        if not gdf.empty:\n",
    "            # 简化几何形状以减少数据量\n",
    "            sim_geo = gdf[\"geometry\"].simplify(tolerance=0.001)\n",
    "            geo_j = sim_geo.to_json()\n",
    "            geo_j = folium.GeoJson(\n",
    "                data=geo_j,\n",
    "                style_function=lambda x: {\"fillColor\": \"green\", \"color\": \"black\", \"weight\": 2, \"fillOpacity\": 0.1}\n",
    "            )\n",
    "            # 添加城市名称的弹出框\n",
    "            folium.Popup(city).add_to(geo_j)\n",
    "            geo_j.add_to(m)\n",
    "    except Exception as e:\n",
    "        print(f\"Error fetching data for {city}: {e}\")\n",
    "m.save(\"data/graphgCmsclRoute02_boarder.html\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-09T07:33:03.537767700Z",
     "start_time": "2025-03-09T07:32:59.945421300Z"
    }
   },
   "execution_count": 57
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "python3",
   "language": "python",
   "display_name": "Python 3 (ipykernel)"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
